/*******************************************************************
This file is part of iDialer.

iDialer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

iDialer is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with iDialer.  If not, see <http://www.gnu.org/licenses/>.
*******************************************************************/

#include "stdafx.h"
#include "wfmtmidi.h"

// http://blogs.msdn.com/medmedia/archive/2007/01/03/the-wavedev2-midi-implementation.aspx
/*
DTMF frequencies:

DTMF stands for Dual Tone Multi Frequency. These are the tones you get when
you press a key on your telephone touchpad. The tone of the button is the
sum of the column and row tones. The ABCD keys do not exist on standard
telephones.

                        Frequency 1

                    1209  1336  1477  1633

                697   1     2     3     A

                770   4     5     6     B
Frequency 2
                852   7     8     9     C

                941   *     0     #     D

Frequencies of other telephone tones

Type                Hz          On      Off
---------------------------------------------------------------------
Dial Tone         350 & 400     ---     ---
Busy Signal       480 & 620     0.5     0.5
Toll Congestion   480 & 620     0.2     0.3
Ringback (Normal) 440 & 480     2.0     4.0
Ringback (PBX)    440 & 480     1.5     4.5
Reorder (Local)   480 & 620     3.0     2.0
Invalid Number    200 & 400
Hang Up Warning 1400 & 2060     0.1     0.1
Hang Up         2450 & 2600     ---     ---
*/

HWAVEOUT hWaveOut = 0;
WAVEHDR WaveHdr = {0};

// Create a buffer for 3 midi messages
WAVEFORMAT_MIDI_MESSAGE MidiMessage[3];

int PlayDTMF(TCHAR digit, UINT uVolume) {
    WAVEFORMAT_MIDI wfm = {0};
    MMRESULT mmResult;

    wfm.wfx.wFormatTag = WAVE_FORMAT_MIDI;
    wfm.wfx.nBlockAlign = sizeof(WAVEFORMAT_MIDI_MESSAGE);
    wfm.wfx.cbSize = WAVEFORMAT_MIDI_EXTRASIZE;
    wfm.wfx.nChannels = 1;

    // Force each tick to be 1 sec
    wfm.USecPerQuarterNote = 1000000;
    wfm.TicksPerQuarterNote = 1;

    // Calculate the 2 parts of the DTMF tone
    int freq1 
        = digit == '1' || digit == '4' || digit == '7' || digit == '*' ? 1209
        : digit == '2' || digit == '5' || digit == '8' || digit == '0' ? 1336
        : digit == '3' || digit == '6' || digit == '9' || digit == '#' ? 1477
        : 0;
    int freq2
        = digit == '1' || digit == '2' || digit == '3' ? 697
        : digit == '4' || digit == '5' || digit == '6' ? 770
        : digit == '7' || digit == '8' || digit == '9' ? 852
        : digit == '*' || digit == '0' || digit == '#' ? 941
        : 0;

    if (!freq1 || !freq2)
        return -1;


    MidiMessage[0].DeltaTicks = 0;
    MidiMessage[0].MidiMsg = 0x207F0000 | freq1;

    MidiMessage[1].DeltaTicks = 0;
    MidiMessage[1].MidiMsg = 0x207F0000 | freq2;

    // play for 10 seconds max
    MidiMessage[2].DeltaTicks = 10;
    MidiMessage[2].MidiMsg = 0;

    // Play it!

    if (NULL == hWaveOut) {
        // Point wave header to MIDI data
        WaveHdr.lpData = (LPSTR)MidiMessage;
        WaveHdr.dwBufferLength = sizeof(MidiMessage);

        mmResult = waveOutOpen(&hWaveOut, 0, (LPWAVEFORMATEX)&wfm, 
            NULL, 0, CALLBACK_NULL);
        
        if (mmResult != MMSYSERR_NOERROR)
            return -1;

        mmResult = waveOutSetVolume(hWaveOut, uVolume);
        mmResult = waveOutPrepareHeader(hWaveOut, &WaveHdr, sizeof(WaveHdr));
    }
    mmResult = waveOutWrite(hWaveOut, &WaveHdr, sizeof(WaveHdr));

    return 0;
}

void StopDTMF(void) {
    MMRESULT mmResult;

    if (NULL != hWaveOut) {
        mmResult = waveOutReset(hWaveOut);
        //TODO: put this cleanup _some_where
        mmResult = waveOutUnprepareHeader(hWaveOut, &WaveHdr, sizeof(WaveHdr));
        mmResult = waveOutClose(hWaveOut);
        hWaveOut = 0;
    }
}